﻿// Copyright (c) 2024 刻BITTER
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.


#pragma once

#include <cstddef>
#include <cstdint>

#include "lipid_filter.hpp"

// 与PID 数据的输入 / 输出有关
namespace lipid {

    template <typename V, typename R>
    class Forward {
       public:
        using FilterType = IFilter<V, R>;

       private:
        FilterType* _ftr = nullptr;
        R _cache{};

       public:
        Forward(FilterType* ftr) :
            _ftr(ftr) {}

        void set(V input_val) {
            if (_ftr == nullptr) {
                _cache = input_val;
            }
            else {
                _cache = _ftr->feed(input_val);
            }
        }

        R get() const {
            return _cache;
        }

        void reset(R init_val) {
            _ftr->reset(init_val);
        }

        const FilterType* get_filter() const {
            return _ftr;
        }

        FilterType* get_filter() {
            return _ftr;
        }

        void set_filter(FilterType* ftr) {
            _ftr = ftr;
        }
    };


    template <typename R>
    class ISensor {
       public:
        virtual R update() = 0;

        virtual ~ISensor() {}
    };


    /**
     * @brief 可以将数据暂存起来的传感器接口
     *
     * 在ISensor 基础上增加了一个成员变量_current_val 和对应的getter，子类应该在update 中更新_current_val，
     * 外部调用者可以在update 后多次使用get 获取相同的数据，且不会改变其内部状态
     */
    template <typename R>
    class CachedSensor : public ISensor<R> {
       protected:
        R _current_val = 0;

       public:
        R get() const {
            return _current_val;
        }
    };

    /**
     * @brief 将ISensor 变成CachedSensor 的适配器
     *
     */
    template <typename R>
    class CachedSensorAdapter : public CachedSensor<R> {
       private:
        ISensor<R>& _s;

       public:
        CachedSensorAdapter(ISensor<R>& s) :
            _s(s) {}

        virtual R update() override {
            this->_current_val = _s.update();
            return this->_current_val;
        }
    };


    template <typename V>
    class IActuator {
       public:
        virtual void set(V val) = 0;

        virtual ~IActuator() {}
    };


    /**
     * @brief 可以将数据暂存起来的作动器接口
     */
    template <typename R>
    class CachedActuator : public IActuator<R> {
       protected:
        R _current_val = 0;

       public:
        R get() const {
            return _current_val;
        }
    };

}  // namespace lipid